package com.eedi.framework.permission.service;


import com.eedi.framework.permission.controller.org.vo.role.*;
import com.eedi.framework.common.enums.CommonStatusEnum;
import com.eedi.framework.common.pojo.PageResult;
import com.eedi.framework.permission.controller.org.vo.OrgDeptDataPermissionRespDTO;
import com.eedi.framework.permission.controller.org.vo.menu.OrgMenuListReq;
import com.eedi.framework.permission.controller.org.vo.menu.OrgMenuSaveReq;
import com.eedi.framework.permission.controller.org.vo.permission.OrgPermissionBatchAssignUserRoleResp;
import com.eedi.framework.permission.controller.org.vo.role.*;
import com.eedi.framework.permission.dal.dataobject.OrgMenuDO;
import com.eedi.framework.permission.dal.dataobject.OrgRoleDO;
import com.eedi.framework.permission.enums.OrgDataScopeEnum;
import com.eedi.framework.permission.enums.OrgRoleCodeEnum;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.util.Collections.singleton;

/**
 * 权限 Service 接口
 * <p>
 * 提供用户-角色、角色-菜单、角色-部门的关联权限处理
 *
 * @author 永聚长青源码
 */
public interface OrgPermissionService {

    /**
     * 判断是否有权限，任一一个即可
     *
     * @param userId      用户编号
     * @param permissions 权限
     * @return 是否
     */
    boolean hasAnyPermissions(String userId, String... permissions);

    /**
     * 判断是否有角色，任一一个即可
     *
     * @param roles 角色数组
     * @return 是否
     */
    boolean hasAnyRoles(String userId, String... roles);

    // ========== 角色-菜单的相关方法  ==========

    /**
     * 设置角色菜单
     *
     * @param roleId  角色编号
     * @param menuIds 菜单编号集合
     */
    void assignRoleMenu(String roleId, Set<String> menuIds);

    /**
     * 处理角色删除时，删除关联授权数据
     *
     * @param roleId 角色编号
     */
    void processRoleDeleted(String roleId);

    /**
     * 处理菜单删除时，删除关联授权数据
     *
     * @param menuId 菜单编号
     */
    void processMenuDeleted(String menuId);

    /**
     * 获得角色拥有的菜单编号集合
     *
     * @param roleId 角色编号
     * @return 菜单编号集合
     */
    default Set<String> getRoleMenuListByRoleId(String roleId) {
        return getRoleMenuListByRoleId(singleton(roleId));
    }

    /**
     * 获得角色们拥有的菜单编号集合
     *
     * @param roleIds 角色编号数组
     * @return 菜单编号集合
     */
    Set<String> getRoleMenuListByRoleId(Collection<String> roleIds);

    /**
     * 获得拥有指定菜单的角色编号数组，从缓存中获取
     *
     * @param menuId 菜单编号
     * @return 角色编号数组
     */
    Set<String> getMenuRoleIdListByMenuIdFromCache(String menuId);

    // ========== 用户-角色的相关方法  ==========

    /**
     * 设置用户角色
     *
     * @param userId  角色编号
     * @param roleIds 角色编号集合
     */
    void assignUserRole(String userId, Set<String> roleIds,String orgInfoId);

    /**
     * 处理用户删除时，删除关联授权数据
     *
     * @param userId 用户编号
     */
    void processUserDeleted(String userId);

    /**
     * 获得拥有多个角色的用户编号集合
     *
     * @param roleIds 角色编号集合
     * @return 用户编号集合
     */
    Set<String> getUserRoleIdListByRoleId(Collection<String> roleIds);

    /**
     * 获得用户拥有的角色编号集合
     *
     * @param userId 用户编号
     * @return 角色编号集合
     */
    Set<String> getUserRoleIdListByUserId(String userId);

    /**
     * 获得用户拥有的角色编号集合，从缓存中获取
     *
     * @param userId 用户编号
     * @return 角色编号集合
     */
    Set<String> getUserRoleIdListByUserIdFromCache(String userId);

    // ========== 用户-部门的相关方法  ==========

    /**
     * 设置角色的数据权限
     *
     * @param roleId           角色编号
     * @param dataScope        数据范围
     * @param dataScopeDeptIds 部门编号数组
     */
    void assignRoleDataScope(String roleId, OrgDataScopeEnum dataScope, Set<String> dataScopeDeptIds);

    /**
     * 获得登陆用户的部门数据权限
     *
     * @param userId 用户编号
     * @return 部门数据权限
     */
    OrgDeptDataPermissionRespDTO getDeptDataPermission(String userId);


    /**
     * 创建角色
     *
     * @param createReqVO 创建角色信息
     * @return 角色编号
     */
    String createRole(@Valid OrgRoleSaveReq createReqVO);

    /**
     * 创建角色
     *
     * @param createReq 创建角色信息
     * @return 角色编号
     */
    String createRole(@Valid SysOrgRoleCreateReq createReq);

    /**
     * 预设角色创建
     *
     * @return 角色编号
     */
    Map<String,String> presupposeRole(String orgInfoId);

    /**
     * 默认角色赋权
     */
    void assignDefaultRoleMenu(String orgInfoId,Map<String,String> menuMap,Map<String,String> roleMap);
    /**
     * 更新角色
     *
     * @param updateReqVO 更新角色信息
     */
    void updateRole(@Valid OrgRoleUpdateReq updateReqVO);

    /**
     * 删除角色
     *
     * @param roleId 角色编号
     */
    void deleteRole(String roleId);

    /**
     * 更新角色状态
     *
     * @param roleId 角色编号
     * @param status 状态
     */
    void updateRoleStatus(String roleId, CommonStatusEnum status);

    /**
     * 设置角色的数据权限
     *
     * @param roleId 角色编号
     * @param dataScope 数据范围
     * @param dataScopeDeptIds 部门编号数组
     */
    void updateRoleDataScope(String roleId, OrgDataScopeEnum dataScope, Set<String> dataScopeDeptIds);

    /**
     * 获得角色
     *
     * @param roleId 角色编号
     * @return 角色
     */
    OrgRoleDO getRole(String roleId);

    /**
     * 获得角色，从缓存中
     *
     * @param roleId 角色编号
     * @return 角色
     */
    OrgRoleDO getRoleFromCache(String roleId);

    /**
     * 获得角色列表
     *
     * @param roleIds 角色编号数组
     * @return 角色列表
     */
    List<OrgRoleDO> getRoleList(Collection<String> roleIds);

    /**
     * 获得角色数组，从缓存中
     *
     * @param roleIds 角色编号数组
     * @return 角色数组
     */
    List<OrgRoleDO> getRoleListFromCache(Collection<String> roleIds);

    /**
     * 获得角色列表
     *
     * @param statuses
     * @return
     */
    List<OrgRoleDO> getRoleListByStatus(Collection<CommonStatusEnum> statuses);

    /**
     * 获得所有角色列表
     *
     * @return 角色列表
     */
    List<OrgRoleDO> getRoleList();

    /**
     * 获得角色分页
     *
     * @param reqVO 角色分页查询
     * @return 角色分页结果
     */
    PageResult<OrgRoleDO> getRolePage(OrgRolePageReq reqVO);

    /**
     * 判断角色编号数组中，是否有管理员
     *
     * @param roleIds 角色编号数组
     * @return 是否有管理员
     */
    boolean hasAnySuperAdmin(Collection<String> roleIds);

    /**
     * 校验角色们是否有效。如下情况，视为无效：
     * 1. 角色编号不存在
     * 2. 角色被禁用
     *
     * @param roleIds 角色编号数组
     */
    void validateRoleList(Collection<String> roleIds);

    /**
     * 创建菜单
     *
     * @param createReqVO 菜单信息
     * @return 创建出来的菜单编号
     */
    String createMenu(OrgMenuSaveReq createReqVO);

    /**
     * 更新菜单
     *
     * @param updateReqVO 菜单信息
     */
    void updateMenu(OrgMenuSaveReq updateReqVO);

    /**
     * 删除菜单
     *
     * @param menuId 菜单编号
     */
    void deleteMenu(String menuId);

    /**
     * 获得所有菜单列表
     *
     * @return 菜单列表
     */
    List<OrgMenuDO> getMenuList();

    /**
     * 基于租户，筛选菜单列表
     * 注意，如果是系统租户，返回的还是全菜单
     *
     * @param reqVO 筛选条件请求 VO
     * @return 菜单列表
     */
    List<OrgMenuDO> getMenuListByTenant(OrgMenuListReq reqVO);

    /**
     * 筛选菜单列表
     *
     * @param reqVO 筛选条件请求 VO
     * @return 菜单列表
     */
    List<OrgMenuDO> getMenuList(OrgMenuListReq reqVO);

    /**
     * 获得权限对应的菜单编号数组
     *
     * @param permission 权限标识
     * @return 数组
     */
    List<String> getMenuIdListByPermissionFromCache(String permission);

    /**
     * 获得菜单
     *
     * @param menuId 菜单编号
     * @return 菜单
     */
    OrgMenuDO getMenu(String menuId);

    /**
     * 获得菜单数组
     *
     * @param menuIds 菜单编号数组
     * @return 菜单数组
     */
    List<OrgMenuDO> getMenuList(Collection<String> menuIds);

    /**
     * 获取管理员类型账号数量
     * @return 数量
     */
    Long countAdmin();

    /**
     * 根据用户ID获取角色列表
     * @param orgUserId 用户ID
     * @return 角色列表
     */
    List<OrgRoleSimpleResp> getByOrgUserId(String orgUserId);


    /**
     * 获取指定机构下的超管角色列表
     * @param orgInfoId 机构ID
     * @param orgRoleCodeEnum 角色编码
     * @return 角色列表
     */
    List<OrgRoleDO> getRoleListByOrgInfoIdAndRoleCode(String orgInfoId, OrgRoleCodeEnum orgRoleCodeEnum);

    /**
     * 给机构初始化菜单
     * @param orgInfoId 机构ID
     * @return 菜单ID列表
     */
    Map<String,String>  initOrgInfoDefaultMenus(String orgInfoId);

    /**
     * 给指定机构的超管角色赋予菜单权限
     * @param orgInfoId 机构id
     * @param orgRoleAdminId 机构的超管角色ID
     * @param menuIds 机构下菜单id列表
     */
    void assignRoleMenuByOrgInfoId(String orgInfoId, String orgRoleAdminId, List<String> menuIds);

    /**
     * 下载批量导入用户角色配置的excel模板
     * @param response
     * @throws IOException
     */
    void  excelTemplate(HttpServletResponse response) throws IOException;

    /**
     * 批量赋予用户角色
     * @param fileUrl
     * @return
     * @throws Exception
     */
    OrgPermissionBatchAssignUserRoleResp batchAssignUserRole(String fileUrl) throws Exception;
}
